package com.weiiew.common.config;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.weiiew.common.redis.fuzzyRedisCacheManager;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.io.IOException;
import java.time.Duration;

@Configuration
@EnableCaching
public class RedisConfig {
    public String prefix = "factory:";
    public int liveTime = 1;
    public boolean cacheNullValues = true;


    //------------通用序列化器：处理普通对象（如 User、String 等）--------------
    private RedisSerializer<Object> genericSerializer() {
        ObjectMapper om = new ObjectMapper();
        om.activateDefaultTyping(
                BasicPolymorphicTypeValidator.builder().allowIfSubType(Object.class).build(),
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY
        );
        return new GenericJackson2JsonRedisSerializer(om);
    }
    //----------------------------- 通用配置 -----------------------------
    private RedisCacheConfiguration buildDefaultConfig(RedisSerializer<Object> serializer) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(liveTime))
                .prefixCacheNameWith(prefix)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));

        return cacheNullValues ? config : config.disableCachingNullValues();
    }
    //----------------------------- 通用序列化器 -----------------------------
    @Bean
    @Primary
    public RedisCacheManager defaultCacheManager(RedisConnectionFactory factory) {
        return RedisCacheManager.builder(factory)
                .cacheDefaults(buildDefaultConfig(genericSerializer()))
                .build();
    }

    //----------------------------- Map 专用序列化器 -----------------------------
    @Bean(name = "mapCacheManager")
    public RedisCacheManager mapCacheManager(RedisConnectionFactory factory) {
        return RedisCacheManager.builder(factory)
                .cacheDefaults(buildDefaultConfig(mapSerializer()))
                .build();
    }

    /**
     * 自定义键反序列化器：将字符串键转换为 Integer
     */
    private static class IntegerKeyDeserializer extends KeyDeserializer {
        @Override
        public Integer deserializeKey(String key, DeserializationContext ctxt) throws IOException {
            try {
                return Integer.parseInt(key);
            } catch (NumberFormatException e) {
                throw new IOException("键 '" + key + "' 无法转换为 Integer", e);
            }
        }
    }
    /**
     * Map 专用序列化器：处理 Map<Integer, T>
     */
    private RedisSerializer<Object> mapSerializer() {
        ObjectMapper om = new ObjectMapper();
        // 启用类型信息嵌入
        om.activateDefaultTyping(
                BasicPolymorphicTypeValidator.builder().allowIfSubType(Object.class).build(),
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.PROPERTY
        );

        // 注册自定义模块处理键的反序列化
        SimpleModule module = new SimpleModule();
        module.addKeyDeserializer(Object.class, new IntegerKeyDeserializer());
        om.registerModule(module);

        // 禁用将数字解析为 Long
        om.configure(DeserializationFeature.USE_LONG_FOR_INTS, false);

        return new GenericJackson2JsonRedisSerializer(om);
    }


    //----------------------------- 模糊删除缓存管理器 -----------------------------
    @Bean(name = "fuzzyCacheManager")
    public CacheManager fuzzyCacheManager(RedisConnectionFactory factory) {
        return new fuzzyRedisCacheManager(factory, buildDefaultConfig(genericSerializer()));
    }
}